home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
lisp
/
eulisp
/
you-075a.lha
/
you-075a
/
copy.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-25
|
34KB
|
1,250 lines
/* ******************************************************************** */
/* copy.c copyright (c) university of bath 1992 */
/* */
/* creation of modules */
/* ******************************************************************** */
/*
* $Id: copy.c,v 1.36 1992/11/25 16:48:42 djb Exp $
*
* $Log: copy.c,v $
* Revision 1.36 1992/11/25 16:48:42 djb
* changed args to d-gc's gc_malloc - added gc_enabled
*
* Revision 1.35 1992/10/27 15:27:26 pab
* real changes
*
* Revision 1.31 1992/06/16 19:36:24 pab
* weak wrapper code
*
* Revision 1.30 1992/06/14 16:43:45 pab
* incorporated branch from V1.26
*
* Revision 1.29 1992/05/29 12:18:03 pab
* changed headers
*
* Revision 1.28 1992/05/29 09:53:44 rjb
* ALIGN8 and a NULL -> 0
*
* Revision 1.27 1992/05/29 09:47:44 djb
* hooks for CGC mark+sweep (all #ifdef CGC)
*
* Revision 1.26 1992/04/30 19:41:21 pab
* fiddled with tracing
*
* Revision 1.25 1992/04/30 11:07:31 pab
* lost end-page bug. Lowered rounding
*
* Revision 1.24 1992/04/29 12:33:18 pab
* tracing code added
*
* Revision 1.23 1992/04/27 21:55:42 pab
* if it moves, round it
*
* Revision 1.22 1992/04/26 20:55:46 pab
* fixes for generic version, plus static vector type preliminary support,
* no-sockets fixes
*
* Revision 1.21 1992/03/13 18:06:51 pab
* SysV fixes (mainly relinquishing pages and synchonisation)
*
* Revision 1.20 1992/02/27 15:46:57 pab
* bytecode + error changes
*
* Revision 1.19 1992/02/13 13:49:58 pab
* *** empty log message ***
*
* Revision 1.17 1992/02/11 13:38:04 pab
* removed printing gc_enabled
*
* Revision 1.16 1992/02/10 12:11:41 pab
* fixed circular lists
* gc_enabaled now global
*
* revision 1.12 1991/04/02 21:25:30 kjp
* compiler tidying.
* copying garbage collector. Replaces allocate + garbage.c */
#include "defs.h"
#include "structs.h"
#include "funcalls.h"
#include "global.h"
#include "state.h"
#include "copy.h"
#include "weak.h"
#define N_SLOTS_IN_CLASS N_SLOTS_IN_STRUCT(struct class_structure)
#define N_SLOTS_IN_THREAD N_SLOTS_IN_STRUCT(struct thread_structure)
#define OTHER_SPACE(x) 1-(x)
#define is_newspace(x) \
((gcof(x)&1) ==wspace)
#define forwardof(x) \
(lval_classof(x))
#define set_forwarded(x, new) \
( *(&gcof(x))|=0x2 , forwardof(x)=new)
#define is_forwarded(x) \
((gcof(x))&0x2)
#define HEADERSIZE sizeof(Object_t)
/* should not need to allocate any fixed objects yet... */
#ifdef ALIGN8
#define ROUNDTO 8
#else
#define ROUNDTO 4
#endif
#define ROUND_ADDR(x) ((((int)x)&(ROUNDTO-1))==0 ? (x) : (x)+(ROUNDTO-(((int)x)&(ROUNDTO-1))))
#define is_fixed(x) 0
#ifndef NODEBUG
#define TRACE_GC /* writes allocation logging to a file */
#endif
#ifdef TRACE_GC
#include <time.h>
FILE *trace_file;
int counters[256];
int total_moved;
#endif
/* which space are we in */
static int wspace;
static char *free_ptr;
static char *pg_end;
int gc_paranoia=0;
static int collect_count;
/* BSD + SYSV */
static LispObject GC_thread;
/* SYSV only */
SYSTEM_GLOBAL(SystemSemaphore,GC_sem);
SYSTEM_GLOBAL(SystemSemaphore,Rig_sem);
SYSTEM_GLOBAL(int,GC_state);
static SYSTEM_GLOBAL(int,GC_register); /* Who's arrived so far... */
static SYSTEM_GLOBAL(int,GC_exit_register); /* Who's left... */
static SYSTEM_GLOBAL(int,GC_turn); /* whose go */
static SYSTEM_GLOBAL(int,gc_enabled); /* can we... */
static SYSTEM_GLOBAL_ARRAY1(LispObject,GC_register_array,MAX_PROCESSORS);
static LispObject GC_tame_continue;
static SYSTEM_GLOBAL(PageList, old_pages);
/* Valid only in non-gc time */
static SYSTEM_GLOBAL(PageList, free_pages);
static SYSTEM_GLOBAL(int,npages);
static SYSTEM_GLOBAL(int,pagelim);
static SYSTEM_GLOBAL(LispObject, weak_list);
static PageList current_page;
static PageList used_pages;
/* Called from inside copier */
#define ALLOC_SPACE(new,type,ptr,size) \
{ \
new= (type) ptr; \
ptr+=size; \
if (ptr>=pg_end) \
{ \
GRAB_PAGE(NULL,ptr,pg_end); \
new= (type) ptr; \
ptr+=size; \
} \
}
#ifdef MACHINE_ANY
#define GRAB_PAGE_INTERNAL(stacktop,ptr,top) \
{ \
ptr=free_pages->start; \
top=free_pages->end; \
current_page=free_pages; \
free_pages=free_pages->next; \
current_page->next=used_pages; \
used_pages=current_page; \
npages++; \
COPY_BUG(fprintf(stderr,"{Grab: %d}", \
current_page->id)); \
}
#define GRAB_PAGE(x,y,z) GRAB_PAGE_INTERNAL(x,y,z)
#else
#define GRAB_PAGE_INTERNAL(stacktop,ptr,top) \
{ \
ptr=ROUND_ADDR(S_G_V(free_pages)->start); \
top=S_G_V(free_pages)->end; \
current_page=S_G_V(free_pages); \
S_G_V(free_pages)=S_G_V(free_pages)->next; \
current_page->next=used_pages; \
used_pages=current_page; \
S_G_V(npages)++; \
COPY_BUG(fprintf(stderr,"{Grab(%d): %d}", \
system_scheduler_number, \
current_page->id)); \
COPY_BUG(memset(ptr,'x',top-ptr)); \
}
#define GRAB_PAGE(stacktop,ptr,top) \
{ \
system_open_semaphore(stacktop,&S_G_V(GC_sem)); \
GRAB_PAGE_INTERNAL(stacktop,ptr,top); \
system_close_semaphore(&S_G_V(GC_sem)); \
}
#endif
#define MAYBE_GRAB_PAGE(res,stacktop,ptr,top) \
{ \
system_open_semaphore(stacktop,&S_G_V(GC_sem)); \
if (S_G_V(npages)<S_G_V(pagelim)) \
{ \
GRAB_PAGE_INTERNAL(stacktop,ptr,top); \
res=1; \
} \
else \
res=0; \
/**/ \
system_close_semaphore(&S_G_V(GC_sem)); \
}
#define PRINT_LISTS(stream) \
{ \
PageList xx; \
fputs("Free: ",stream); \
xx=S_G_V(free_pages); \
while (xx!=NULL) \
{ fprintf(stream,"%d ",xx->id); \
xx=xx->next; \
} \
fputs("\nUsed: ",stream); \
xx=used_pages; \
while (xx!=NULL) \
{ fprintf(stream,"%d ",xx->id); \
xx=xx->next; \
} \
fputc('\n',stream); \
}
void init_allocator(int size)
{
#ifdef DGC
gc_init(size);
#else
PageList *newpage;
char *space=system_malloc(2*size);
char *end=space+2*size;
int pg_count=0;
COPY_BUG(memset(space,'T',2*size));
#endif
#ifndef MACHINE_ANY
SYSTEM_INITIALISE_GLOBAL(SystemSemaphore,GC_sem,NULL);
system_allocate_semaphore(&S_G_V(GC_sem));
SYSTEM_INITIALISE_GLOBAL(SystemSemaphore,Rig_sem,NULL);
system_allocate_semaphore(&S_G_V(Rig_sem));
SYSTEM_INITIALISE_GLOBAL(int,GC_state,GC_DONE);
SYSTEM_INITIALISE_GLOBAL(int,GC_register,0);
SYSTEM_INITIALISE_GLOBAL(int,GC_exit_register,0);
SYSTEM_INITIALISE_GLOBAL(int,pagelim,0);
SYSTEM_INITIALISE_GLOBAL(PageList,free_pages,NULL);
SYSTEM_INITIALISE_GLOBAL(PageList,old_pages,NULL);
SYSTEM_INITIALISE_GLOBAL(int,npages,NULL);
SYSTEM_INITIALISE_GLOBAL(int,GC_turn,NULL);
SYSTEM_INITIALISE_GLOBAL_ARRAY1(LispObject,
GC_register_array,MAX_PROCESSORS,NULL);
#endif
SYSTEM_INITIALISE_GLOBAL(int,gc_enabled,0);
SYSTEM_INITIALISE_GLOBAL(LispObject,weak_list,NULL);
#ifndef DGC
newpage= &S_G_V(free_pages);
while (space<end)
{
*newpage=(PageList) space;
(*newpage)->status=PAGE_FREE;
(*newpage)->end= ((space+PAGE_SIZE) < end ? space+PAGE_SIZE : end);
(*newpage)->id=pg_count;
newpage= &((*newpage)->next);
space+=PAGE_SIZE;
pg_count++;
}
*newpage=NULL;
printf("Initialised with: %x [%d pages]\n",size,pg_count);
COPY_BUG(PRINT_LISTS(stderr));
used_pages=NULL;
wspace=0;
S_G_V(pagelim)=pg_count/2;
S_G_V(npages)=0;
GRAB_PAGE(NULL,free_ptr,pg_end);
#endif
}
void runtime_initialise_garbage_collector(LispObject *stacktop)
{
(GC_tame_continue)=allocate_continue(stacktop);
GC_thread=nil;
add_root(&GC_tame_continue);
add_root(&GC_thread);
}
void initialise_garbage(LispObject *stacktop)
{ /* Pretend we're a module */
LispObject garbage_collect(LispObject *);
GC_thread = allocate_thread(stacktop,2048,1024,0);
(void) make_module_function(stacktop,"GC",garbage_collect,0);
}
/* Called when a new process forks */
#ifndef MACHINE_ANY
void runtime_reset_allocator(LispObject *stacktop)
{
COPY_BUG(fprintf(stderr,"Proc: %d starting\n",system_scheduler_number));
used_pages=NULL;
GRAB_PAGE(NULL,free_ptr,pg_end);
GC_thread = allocate_thread(stacktop,2048,1024,0);
add_root(&GC_thread);
(GC_tame_continue)=allocate_continue(stacktop);
add_root(&GC_tame_continue);
system_open_semaphore(stacktop,&S_G_V(Rig_sem));
RIG_GC_THREAD(stacktop);
system_close_semaphore(&S_G_V(Rig_sem));
}
#endif
EUFUN_0(garbage_collect)
{
void do_gc_sync(LispObject *);
do_gc_sync(stacktop);
return nil;
}
EUFUN_CLOSE
int current_space()
{
return wspace;
}
#ifndef MACHINE_ANY
extern void rig_gc_thread(LispObject *stacktop)
{
#ifndef MACHINE_ANY
RIG_GC_THREAD(stacktop);
#endif
}
#endif
/* c-roots */
#define MAXROOTS 300
int nroots=0;
LispObject *roots[MAXROOTS];
int add_root(LispObject *root)
{
int x=nroots;
roots[nroots++]=root;
return x;
}
void copy_root(LispObject *x)
{
LispObject copy_object(LispObject);
*x=copy_object(*x);
}
void copy_on()
{
S_G_V(gc_enabled)++;
COPY_BUG(fprintf(stderr,"{+%d}",S_G_V(gc_enabled)));
}
void copy_off()
{
S_G_V(gc_enabled)--;
COPY_BUG(fprintf(stderr,"{-%d}",S_G_V(gc_enabled)));
}
/* These will have to more complicated eventually */
void ON_collect()
{
S_G_V(gc_enabled)++;
COPY_BUG(fprintf(stderr,"{+%d}",S_G_V(gc_enabled)));
}
void OFF_collect()
{
S_G_V(gc_enabled)--;
COPY_BUG(fprintf(stderr,"{-%d}",S_G_V(gc_enabled)));
}
/****************************************
* allocation
****************************************/
static int a_count;
#define ALLOC_GAP 2048
int alloc_gap=ALLOC_GAP;
#ifdef DGC
LispObject *the_stacktop;
LispObject allocate_nbytes(LispObject *stacktop,int n,int type)
{
LispObject object;
the_stacktop = stacktop;
object=(LispObject)gc_malloc(n,S_G_V(gc_enabled));
lval_typeof(object)=type;
return(object);
}
#else
LispObject allocate_nbytes(LispObject *stacktop,int n,int type)
{
void do_gc_sync(LispObject *);
LispObject object;
char *new;
COPY_BUG(if (n<HEADERSIZE) fprintf(stderr,"Object too small to hold header\n") );
#ifdef TRACE_GC
counters[type&255]++;
#endif
#ifndef NODEBUG
if (gc_paranoia)
fprintf(stdout,"{%x:%d}",type,n);
#endif
n=ROUND_ADDR(n);
a_count+=n;
#ifdef NODEBUG
if ( !(free_ptr+n<pg_end))
#else
if ((gc_paranoia && a_count>alloc_gap && S_G_V(gc_enabled))
|| !(free_ptr+n<pg_end))
#endif
{
int res;
MAYBE_GRAB_PAGE(res,stacktop,free_ptr,pg_end);
if (!res)
{
a_count=0;
if (S_G_V(gc_enabled)<1)
{
fprintf(stderr,"{Grabbed Page 'cos I couldn't GC[%d]}\n",S_G_V(gc_enabled));
GRAB_PAGE(stacktop,free_ptr,pg_end);
}
else
{
do_gc_sync(stacktop);
}
}
}
ALLOC_SPACE(object,LispObject,free_ptr,n);
lval_typeof(object)=type;
gcof(object)=(short)wspace;
return(object);
}
#endif
#ifdef MACHINE_ANY
void do_gc_sync(LispObject *stacktop)
{
static void free_old_pages(void);
static void swap_spaces(LispObject *);
static void free_weak_ptrs(void);
fprintf(stderr,"Collection %d initiated: %d used, %d bytes (%d%%) remaining\n",
collect_count,S_G_V(npages)*PAGE_SIZE,(S_G_V(pagelim)-S_G_V(npages))*PAGE_SIZE,0);
S_G_V(old_pages)=NULL;
S_G_V(npages)=0;
S_G_V(weak_list)=NULL;
swap_spaces(stacktop);
free_old_pgs();
free_weak_ptrs();
}
#else /* ! MACHINE_ANY */
void do_gc_sync(LispObject *stacktop)
{
static void free_weak_ptrs(void);
static void free_old_pages(void);
int i;
#ifdef DGC
void tidy_stacks(LispObject *);
tidy_stacks(the_stacktop);
stacktop = the_stacktop;
#endif
/* we must save state early */
save_state(stacktop,CURRENT_THREAD()->THREAD.state);
/* Wait for the last gc to finish */
while ( S_G_V(GC_state)!=GC_DONE
&&S_G_V(GC_state)!=GC_SINKING)
;
/* register myself */
system_open_semaphore(stacktop,&S_G_V(GC_sem));
++S_G_V(GC_register);
if (S_G_V(GC_register) == 1)
{ /* First */
S_G_V(GC_state) = GC_SINKING;
fprintf(stderr,"GC sinking(%d) --- ",S_G_V(gc_enabled));
}
fprintf(stderr,"%d ",system_scheduler_number);
/* if last, set flag */
if (S_G_V(GC_register) == RUNNING_PROCESSORS())
{ /* Last */
S_G_V(GC_state) = GC_REGISTERED;
fprintf(stderr,"\n ",system_scheduler_number); fflush(stdout);
fprintf(stderr,"Collection %d initiated: %d used, %d bytes (%d%%) remaining\n",
collect_count,S_G_V(npages)*PAGE_SIZE,(S_G_V(pagelim)-S_G_V(npages))*PAGE_SIZE,0);
S_G_V(GC_turn)=0;
S_G_V(npages)=0;
S_G_V(old_pages) = NULL;
S_G_V(weak_list)=NULL;
}
system_close_semaphore(&S_G_V(GC_sem));
SYSTEM_GLOBAL_ARRAY1_VALUE(GC_register_array,system_scheduler_number)
= CURRENT_THREAD();
/* boot any sleepers */
system_kick_sleepers();
/* wait until all get the idea */
while (S_G_V(GC_state)!=GC_REGISTERED)
;
/* Save myself */
/* we all copy --- in serial 'cos its easier that way */
while(S_G_V(GC_turn)!=system_scheduler_number)
;
if (!set_continue(stacktop,(GC_tame_continue)))
{
LispObject temp = CURRENT_THREAD();
LispObject *newstack;
COPY_BUG(fprintf(stderr," {Proc: %d leaping %x %x %x}\n",system_scheduler_number,
(GC_tame_continue)->CONTINUE.thread,GC_thread,temp));
newstack = load_thread(GC_thread);
call_continue(newstack,GC_thread->THREAD.state,temp);
}
/* done: should signal this */
S_G_V(GC_turn)++;
if (system_scheduler_number==RUNNING_PROCESSORS()-1)
{
#ifndef DGC
free_old_pgs();
free_weak_ptrs();
#endif
S_G_V(GC_state)=GC_MARKED;
}
while(S_G_V(GC_state)!=GC_MARKED)
;
/* Now we can go */
system_open_semaphore(stacktop,&S_G_V(GC_sem));
--S_G_V(GC_register);
if (S_G_V(GC_register)==0)
S_G_V(GC_state)=GC_DONE;
system_close_semaphore(&S_G_V(GC_sem));
fprintf(stderr,"GC done\n");
}
#ifdef DGC
void gcollect()
{
long time_now;
time_now=time(NULL);
fprintf(stderr,"GC started %s\n",ctime(&time_now));
do_gc_sync(NULL);
time_now=time(NULL);
fprintf(stderr,"GC finished %s\n",ctime(&time_now));
}
#endif
void first_gc_mark_call(LispObject *stacktop)
{
#ifdef DGC
void real_gcollect();
#else
void swap_spaces(LispObject *stacktop);
#endif
LispObject ret;
COPY_BUG(printf("First invokation of GC mark: %x\n",stacktop); fflush(stdout));
stacktop=GC_thread->THREAD.gc_stack_base;
reset:
ret = GC_thread->THREAD.state->CONTINUE.value;
COPY_BUG(printf("Laying continue in GC mark: %x\n",stacktop); fflush(stdout));
if (set_continue(stacktop,(GC_thread->THREAD.state)))
{
goto reset;
}
STACK_TMP(ret);
COPY_BUG(printf("Marking in GC mark\n"); fflush(stdout));
#ifdef DGC
real_gcollect();
#else
swap_spaces(stacktop);
#endif
UNSTACK_TMP(ret);
COPY_BUG(fprintf(stderr,"Jumping back: target: (%x %d) %x %d %d %d %d\n gc_thread: (%x %d) %x %d %d\n",
ret,ret->THREAD.header.gc,
ret->THREAD.state,
ret->THREAD.state->CONTINUE.header.gc,
ret->THREAD.state->CONTINUE.header.type,
ret->THREAD.state->CONTINUE.handler_stack->CONS.header.type,
ret->THREAD.state->CONTINUE.handler_stack->CONS.header.gc,
GC_thread,
GC_thread->THREAD.header.gc,
GC_thread->THREAD.state,
GC_thread->THREAD.state->CONTINUE.header.gc,
GC_thread->THREAD.state->CONTINUE.header.type);
fflush(stdout));
/**save_state(stacktop,GC_thread);**/
(void) load_thread(ret); /* this returns the wrong value for our porpoises */
call_continue(NULL,(GC_tame_continue),nil);
}
#endif
/* Collection */
void swap_spaces(LispObject *stacktop)
{
void copy_root(LispObject *);
void show_stack_space(void);
static void free_old_pgs(void);
char *oldspace;
PageList pg,tmp,*ptr;
int i;
#ifdef TRACE_GC
{
long time_now;
char *str;
int k,j=0;
if (trace_file==NULL)
{
char *buf[20];
sprintf(buf,"/tmp/gc.%d",getpid());
trace_file=fopen(buf,"w");
}
time_now=time(NULL);
str=ctime(&time_now);
fprintf(trace_file,"GC %d started: %s\n",collect_count,str);
fprintf(trace_file,"Used: %d\n",S_G_V(npages)*PAGE_SIZE);
for (k=0; k<255; k++)
{
if (counters[k]!=0)
{
fprintf(trace_file,"%d: %6d ",k,counters[k]);
if ((++j)%6==0)
fputc('\n',trace_file);
}
counters[k]=0;
}
total_moved=0;
fputc('\n',trace_file);
PRINT_LISTS(trace_file);
fflush(trace_file);
}
#endif
/* make sure that all is well */
save_state(stacktop,CURRENT_THREAD()->THREAD.state);
COPY_BUG(PRINT_LISTS(stderr));
pg=current_page;
used_pages=NULL;
wspace=1-wspace;
/* begin the copy process */
GRAB_PAGE(stacktop,free_ptr,pg_end);
for (i=0; i < nroots; i++)
copy_root(roots[i]);
/* Free all oldspace */
/* Assumes that free_pages is unlocked */
while (pg!=NULL)
{ /* insertion sort on the old pages */
tmp=pg->next;
ptr=&S_G_V(old_pages);
if (*ptr!=NULL)
{
while ((*ptr)->next!=NULL
&& (*ptr)->next->id < pg->id)
ptr=&(*ptr)->next;
pg->next=(*ptr)->next;
(*ptr)->next=pg;
}
else
{
*ptr=pg;
pg->next=NULL;
}
pg=tmp;
}
fprintf(stderr,"Collection Completed: %d used, %d bytes (%d%%) remaining\n",
S_G_V(npages)*PAGE_SIZE,
(S_G_V(pagelim)-S_G_V(npages))*PAGE_SIZE,
((S_G_V(pagelim)-S_G_V(npages))*100)/
S_G_V(pagelim));
show_stack_space();
collect_count++;
COPY_BUG(PRINT_LISTS(stderr));
#ifdef TRACE_GC
{
long time_now;
char *str;
int k,j;
time_now=time(NULL);
str=ctime(&time_now);
fprintf(trace_file,"Using: %d\n",S_G_V(npages)*PAGE_SIZE);
PRINT_LISTS(trace_file);
fprintf(trace_file,"Totals: %d\n",total_moved);
for (k=0,j=0; k<255; k++)
{
if (counters[k]!=0)
{
fprintf(trace_file,"%d: %6d ",k,counters[k]);
if ((++j)%6==0)
fputc('\n',trace_file);
counters[k]=0;
}
}
fprintf(trace_file,"GC %d complete: %s\n",collect_count,str);
fflush(trace_file);
}
#endif
return;
}
static void free_old_pgs()
{
PageList tmp;
tmp=S_G_V(free_pages);
if (tmp==NULL)
S_G_V(free_pages)=S_G_V(old_pages);
else
{
while(tmp->next!=NULL)
{
tmp=tmp->next;
}
tmp->next=S_G_V(old_pages);
}
}
void free_weak_ptrs()
{
LispObject wptr;
wptr=S_G_V(weak_list);
while (wptr!=NULL)
{
if (is_forwarded(weak_ptr_val(wptr)))
weak_ptr_val(wptr)=forwardof(weak_ptr_val(wptr));
else
weak_ptr_val(wptr)=nil;
wptr=weak_ptr_chain(wptr);
}
S_G_V(weak_list)=NULL;
}
#ifndef NODEBUG
#define CAREFUL_DECLS \
LispObject copied;
#ifdef NOLOWTAGINTS
#define copy_obj_careful(x) \
(copied=copy_object(x), \
copied==NULL || ((gcof(copied)&1)==wspace) \
? copied \
: (fprintf(stderr,"Wrong space\n"), system_lisp_exit(0), nil))
#else
#define copy_obj_careful(x) \
(copied=copy_object(x), \
(copied==NULL || is_fixnum(x) || ((gcof(copied)&1)==wspace)) \
? copied \
: (fprintf(stderr,"Wrong space\n"), system_lisp_exit(0), nil))
#endif NOLOWTAGINTS
#else
#define CAREFUL_DECLS
#define copy_obj_careful(x) (copy_object(x))
#endif
#define FORWARD_HEADER(new,obj) \
lval_typeof(new)=lval_typeof(obj); \
gcof(new)=wspace; \
class=lval_classof(obj); \
set_forwarded(obj,new);
#define COPY_ALLOC_SPACE(ptr,size) \
ALLOC_SPACE(new,LispObject,ptr,ROUND_ADDR(size));
/* Hack the stackpointer for GRAB_PAGE */
LispObject copy_object(LispObject obj)
{
int i;
LispObject new;
LispObject class;
CAREFUL_DECLS;
if (obj==NULL) return NULL;
#ifndef NOLOWTAGINTS
if (is_fixnum(obj)) return obj;
#endif
if (is_forwarded(obj))
return forwardof(obj);
if (is_newspace(obj))
return obj;
else
{
#ifdef TRACE_GC
counters[lval_typeof(obj)&255]++;
#endif
switch(lval_typeof(obj))
{
case TYPE_NULL:
#if 0
case TYPE_CONS:
#endif
/* Null is (cons nil nil) with hacked type */
COPY_ALLOC_SPACE(free_ptr, sizeof(struct cons_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
CAR(new)=copy_obj_careful(CAR(obj));
CDR(new)=copy_obj_careful(CDR(obj));
break;
#if 1
case TYPE_CONS:
/* allocate space */
{
LispObject walker,newcons;
int count, max;
COPY_ALLOC_SPACE(free_ptr, sizeof(struct cons_structure));
FORWARD_HEADER(new,obj);
CAR(new)=class;
walker=CDR(obj);
max=1;
/* Note: this loop does not copy anything */
while ( walker!=NULL
#ifdef NOLOWTAGINTS
&& !is_fixnum(walker)
#endif
&& is_cons(walker)
&& !is_forwarded(walker)
&& !is_newspace(walker))
{
ALLOC_SPACE(newcons,LispObject,free_ptr, sizeof(struct cons_structure));
FORWARD_HEADER(newcons,walker);
/* Keep the class safe */
CAR(newcons)=class;
walker=CDR(walker);
max++;
}
/* COPY_BUG(fprintf(stderr,"(List: %d elts",max)); */
newcons=new;
/* This loop does all the copying
end is now the stopping point */
count=0;
walker=obj;
while (count<max)
{
lval_classof(newcons)=copy_obj_careful(CAR(newcons));
CAR(newcons)=copy_obj_careful(CAR(walker));
/* except for the end case equiv to CDR(newcons)=newcons+a bit */
CDR(newcons)=copy_obj_careful(CDR(walker));
walker=CDR(walker);
newcons=CDR(newcons);
count++;
}
}
break;
#endif
#ifdef NOLOWTAGINTS
case TYPE_INT:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct integer_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
intval(new)=intval(obj);
break;
#endif
case TYPE_ENV:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct envobject));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
new->ENV.variable = copy_obj_careful(obj->ENV.variable);
new->ENV.value = copy_obj_careful(obj->ENV.value);
new->ENV.next = (Env) copy_obj_careful((LispObject)obj->ENV.next);
new->ENV.mutable = copy_obj_careful(obj->ENV.mutable);
break;
case TYPE_B_MACRO:
case TYPE_METHOD:
case TYPE_GENERIC:
case TYPE_B_FUNCTION:
case TYPE_INSTANCE:
/* allocate space */
i=lval_classof(obj)->CLASS.local_count;
COPY_ALLOC_SPACE(free_ptr, sizeof(Object_t)+ i*sizeof(LispObject));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
for (i=0 ; i<class->CLASS.local_count ; i++)
slotref(new,i) = copy_obj_careful(slotref(obj,i));
break;
case TYPE_VECTOR:
case TYPE_VECTOR|STATIC_TYPE:
if (is_static(obj))
{
gcof(obj)=wspace; new=obj;
class=lval_classof(obj);
}
else
{
COPY_ALLOC_SPACE(free_ptr,sizeof(Object_t)+sizeof(int)+sizeof(LispObject)*obj->VECTOR.length);
FORWARD_HEADER(new,obj);
}
lval_classof(new)= copy_obj_careful(class);
new->VECTOR.length=obj->VECTOR.length;
for (i=0; i<obj->VECTOR.length; i++)
vref(new,i) = copy_obj_careful(vref(obj,i));
break;
case TYPE_STRING:
COPY_ALLOC_SPACE(free_ptr,ROUND_ADDR(sizeof(Object_t)+obj->STRING.length+sizeof(int)));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
new->STRING.length=obj->STRING.length;
memcpy(stringof(new),stringof(obj),obj->STRING.length);
break;
case TYPE_CLASS:
i=lval_classof(obj)->CLASS.local_count;
COPY_ALLOC_SPACE(free_ptr, sizeof(Object_t)+ i*sizeof(LispObject));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
(new->CLASS).name = copy_obj_careful(obj->CLASS.name);
(new->CLASS).superclasses = copy_obj_careful(obj->CLASS.superclasses);
(new->CLASS).subclasses = copy_obj_careful(obj->CLASS.subclasses);
(new->CLASS).slot_table = copy_obj_careful(obj->CLASS.slot_table);
(new->CLASS).slot_list = copy_obj_careful(obj->CLASS.slot_list);
(new->CLASS).direct_slot_list = copy_obj_careful(obj->CLASS.direct_slot_list);
(new->CLASS).precedence = copy_obj_careful(obj->CLASS.precedence);
(new->CLASS).local_count = obj->CLASS.local_count;
for (i=N_SLOTS_IN_CLASS ; i<class->CLASS.local_count ; i++)
slotref(new,i) = copy_obj_careful(slotref(obj,i));
break;
case TYPE_CHAR:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct character_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
new->CHAR.font=obj->CHAR.font;
new->CHAR.code=obj->CHAR.code;
break;
case TYPE_TABLE:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct table_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
new->TABLE.comparator=obj->TABLE.comparator;
new->TABLE.lisp_comparator= copy_obj_careful(obj->TABLE.lisp_comparator);
new->TABLE.tree= copy_obj_careful(obj->TABLE.tree);
break;
case TYPE_CONTINUE:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct continue_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
(new->CONTINUE).thread = copy_obj_careful(obj->CONTINUE.thread);
(new->CONTINUE).value = copy_obj_careful(obj->CONTINUE.value);
(new->CONTINUE).target = copy_obj_careful((obj->CONTINUE).target);
bcopy((char*)(obj->CONTINUE).machine_state,
(char *)new->CONTINUE.machine_state,
sizeof(new->CONTINUE.machine_state));
(new->CONTINUE).gc_stack_pointer = obj->CONTINUE.gc_stack_pointer;
(new->CONTINUE).dynamic_env = (Env)copy_obj_careful((LispObject)obj->CONTINUE.dynamic_env);
(new->CONTINUE).last_continue = copy_obj_careful(obj->CONTINUE.last_continue);
(new->CONTINUE).handler_stack = copy_obj_careful(obj->CONTINUE.handler_stack);
(new->CONTINUE).dp = copy_obj_careful(obj->CONTINUE.dp);
(new->CONTINUE).live = obj->CONTINUE.live;
(new->CONTINUE).unwind = obj->CONTINUE.unwind;
break;
case TYPE_SPECIAL:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct special_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
new->SPECIAL.name = copy_obj_careful(obj->SPECIAL.name);
new->SPECIAL.env = (Env)copy_obj_careful((LispObject)obj->SPECIAL.env);
new->SPECIAL.func = obj->SPECIAL.func;
break;
case TYPE_SYMBOL:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct symbol_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
(new->SYMBOL).pname = copy_obj_careful(obj->SYMBOL.pname);
(new->SYMBOL).lvalue = copy_obj_careful(obj->SYMBOL.lvalue);
(new->SYMBOL).lmodule = copy_obj_careful(obj->SYMBOL.lmodule);
(new->SYMBOL).gvalue = copy_obj_careful(obj->SYMBOL.gvalue);
(new->SYMBOL).plist = copy_obj_careful(obj->SYMBOL.plist);
(new->SYMBOL).left = copy_obj_careful(obj->SYMBOL.left);
(new->SYMBOL).right = copy_obj_careful(obj->SYMBOL.right);
(new->SYMBOL).lhash = copy_obj_careful(obj->SYMBOL.lhash);
(new->SYMBOL).hash = (obj->SYMBOL.hash);
break;
case TYPE_STREAM:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct stream_structure));
FORWARD_HEADER(new,obj);
lval_classof(new) = copy_obj_careful(class);
(new->STREAM).handle = obj->STREAM.handle;
(new->STREAM).name = copy_obj_careful(obj->STREAM.name);
(new->STREAM).mode = obj->STREAM.mode;
(new->STREAM).curchar = new->STREAM.curchar;
break;
case TYPE_C_MODULE: /* These are statically allocated, so just mark */
/* forward to here -- unset fwd bit+ set right space */
gcof(obj)=wspace; new=obj;
class=lval_classof(obj);
lval_classof(obj)=copy_obj_careful(class);
obj->C_MODULE.name=copy_obj_careful(obj->C_MODULE.name);
obj->C_MODULE.home=copy_obj_careful(obj->C_MODULE.home);
obj->C_MODULE.imported_modules=copy_obj_careful(obj->C_MODULE.imported_modules);
obj->C_MODULE.exported_names=copy_obj_careful(obj->C_MODULE.exported_names);
obj->C_MODULE.bindings=copy_obj_careful(obj->C_MODULE.bindings);
obj->C_MODULE.entry_count=copy_obj_careful(obj->C_MODULE.entry_count);
obj->C_MODULE.values=copy_obj_careful(obj->C_MODULE.values);
break;
case TYPE_I_MODULE:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct i_module_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)= copy_obj_careful(class);
new->I_MODULE.name= copy_obj_careful(obj->I_MODULE.name);
new->I_MODULE.home= copy_obj_careful(obj->I_MODULE.home);
new->I_MODULE.imported_modules= copy_obj_careful(obj->I_MODULE.imported_modules);
new->I_MODULE.exported_names= copy_obj_careful(obj->I_MODULE.exported_names);
new->I_MODULE.bindings= copy_obj_careful(obj->I_MODULE.bindings);
new->I_MODULE.bounce_flag= obj->I_MODULE.bounce_flag;
break;
case TYPE_C_FUNCTION:
case TYPE_C_MACRO:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct c_function_structure));
FORWARD_HEADER(new,obj);
lval_classof(new) = copy_obj_careful(class);
new->C_FUNCTION.name = copy_obj_careful(obj->C_FUNCTION.name);
new->C_FUNCTION.home = copy_obj_careful(obj->C_FUNCTION.home);
new->C_FUNCTION.env = (Env)copy_obj_careful((LispObject)obj->C_FUNCTION.env);
new->C_FUNCTION.argtype = obj->C_FUNCTION.argtype;
new->C_FUNCTION.func=obj->C_FUNCTION.func;
break;
case TYPE_I_FUNCTION:
case TYPE_I_MACRO:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct i_function_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
new->I_FUNCTION.name=copy_obj_careful(obj->I_FUNCTION.name);
new->I_FUNCTION.home=copy_obj_careful(obj->I_FUNCTION.home);
new->I_FUNCTION.env=(Env)copy_obj_careful((LispObject)obj->I_FUNCTION.env);
new->I_FUNCTION.bvl=copy_obj_careful(obj->I_FUNCTION.bvl);
new->I_FUNCTION.body=copy_obj_careful(obj->I_FUNCTION.body);
new->I_FUNCTION.argtype=obj->I_FUNCTION.argtype;
break;
case TYPE_FLOAT:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct float_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
new->FLOAT.fvalue=obj->FLOAT.fvalue;
break;
#if (defined(WITH_BSD_SOCKETS) || defined(WITH_SYSTEMV_SOCKETS))
case TYPE_LISTENER:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct listener_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
bcopy(&(obj->LISTENER.socket),&(new->LISTENER.socket),sizeof(new->LISTENER.socket));
bcopy(&(obj->LISTENER.name),&(new->LISTENER.name),sizeof(new->LISTENER.name));
bcopy(&(obj->LISTENER.state),&(new->LISTENER.state),sizeof(new->LISTENER.state));
break;
case TYPE_SOCKET:
COPY_ALLOC_SPACE(free_ptr,sizeof(struct socket_structure));
FORWARD_HEADER(new,obj);
lval_classof(new)=copy_obj_careful(class);
bcopy(&(obj->SOCKET.socket),&(new->SOCKET.socket),sizeof(new->SOCKET.socket));
bcopy(&(obj->SOCKET.name),&(new->SOCKET.name),sizeof(new->SOCKET.name));
bcopy(&(obj->SOCKET.state),&(new->SOCKET.state),sizeof(new->SOCKET.state));
bcopy((obj->SOCKET.buffer),(new->SOCKET.buffer),sizeof(new->SOCKET.buffer));
break;
#endif
case TYPE_THREAD:
i=lval_classof(obj)->CLASS.local_count;
COPY_ALLOC_SPACE(free_ptr, sizeof(Object_t)+ i*sizeof(LispObject));
FORWARD_HEADER(new,obj);
lval_classof(new) = copy_obj_careful(class);
new->THREAD.stack_size = obj->THREAD.stack_size;
new->THREAD.gc_stack_size = obj->THREAD.gc_stack_size;
new->THREAD.fun = copy_obj_careful(obj->THREAD.fun);
new->THREAD.args = copy_obj_careful(obj->THREAD.args);
new->THREAD.value = copy_obj_careful(obj->THREAD.value);
new->THREAD.status = obj->THREAD.status;
new->THREAD.parent = copy_obj_careful(obj->THREAD.parent);
new->THREAD.cochain = copy_obj_careful(obj->THREAD.cochain);
new->THREAD.state = copy_obj_careful(obj->THREAD.state);
new->THREAD.stack_base = obj->THREAD.stack_base;
new->THREAD.gc_stack_base = obj->THREAD.gc_stack_base;
for (i=N_SLOTS_IN_THREAD ; i<class->CLASS.local_count ; i++)
slotref(new,i) = copy_obj_careful(slotref(obj,i));
/* hack */
if (obj->THREAD.gc_stack_base+obj->THREAD.gc_stack_size < obj->THREAD.state->CONTINUE.gc_stack_pointer)
fprintf(stderr,"GC Stack overflow detected\n");
{
LispObject *x=obj->THREAD.gc_stack_base;
while (x<obj->THREAD.state->CONTINUE.gc_stack_pointer)
{
if (!(((int) *x)&1)) /* Check for tags here */
*x = copy_obj_careful(*x);
++x;
}
}
break;
case TYPE_WEAK_WRAPPER:
COPY_ALLOC_SPACE(free_ptr,WEAK_PTR_SIZE*sizeof(LispObject)+sizeof(Object_t));
FORWARD_HEADER(new,obj);
lval_classof(new) = copy_obj_careful(class);
weak_ptr_chain(new)=S_G_V(weak_list);
weak_ptr_val(new)=weak_ptr_val(obj);
S_G_V(weak_list)=new;
break;
default:
fprintf(stderr,"Can't copy: %x\n",typeof(obj));
return obj;
break;
}
return new;
}
}
/*****************************************/
/* Old code */
#ifdef NOWAY /* Attempt to allocate n objects --- not really viable
static char * allocate_bytes(LispObject *stacktop,int n);
LispObject allocate_nbytes(LispObject *stacktop, int size, int type)
{
LispObject object;
object=(LispObject) allocate_bytes(stacktop,size);
lval_typeof(object)=type;
gcof(object)=(short)wspace;
return(object);
}
LispObject allocate_cbytes(LispObject *stacktop, int n, int size, int type)
{
char *space,*ptr;
int i;
/* Hope to get lucky of alignment */
space= allocate_bytes(stacktop,size*n);
ptr=space;
for (i=0; i<n; i++)
{
LispObject new;
new=(LispObject)ptr;
lval_typeof(new)=type;
gcof(new)=wspace;
ptr+=size;
}
return (LispObject) space;
}
#endif